// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
//============================================================================
//  File:       PortCache.cs 
//  Author:   [....]@Microsoft.Com 
//  Summary:    Implements a cache for port handles
// 
//=========================================================================

using System;
using System.Collections; 
using System.Threading;
using System.Security.Principal; 
 
namespace System.Runtime.Remoting.Channels.Ipc
{ 
    internal class PortConnection
    {
        private IpcPort _port;
        private DateTime _socketLastUsed; 

        internal PortConnection(IpcPort port) 
        { 
            _port = port;
            _socketLastUsed = DateTime.Now; 
        }

        internal IpcPort Port { get { return _port; } }
        internal DateTime LastUsed { get { return _socketLastUsed; } } 
    }
 
    internal class ConnectionCache 
    {
        // collection of RemoteConnection's. 
        private static Hashtable _connections = new Hashtable();

        // socket timeout data
        private static RegisteredWaitHandle _registeredWaitHandle; 
        private static WaitOrTimerCallback _socketTimeoutDelegate;
        private static AutoResetEvent _socketTimeoutWaitHandle; 
        private static TimeSpan _socketTimeoutPollTime = TimeSpan.FromSeconds(10); 
        private static TimeSpan _portLifetime = TimeSpan.FromSeconds(10);
 
        static ConnectionCache()
        {
            InitializeConnectionTimeoutHandler();
        } 

        private static void InitializeConnectionTimeoutHandler() 
        { 
            _socketTimeoutDelegate = new WaitOrTimerCallback(TimeoutConnections);
            _socketTimeoutWaitHandle = new AutoResetEvent(false); 
            _registeredWaitHandle =
                ThreadPool.UnsafeRegisterWaitForSingleObject(
                    _socketTimeoutWaitHandle,
                    _socketTimeoutDelegate, 
                    "IpcConnectionTimeout",
                    _socketTimeoutPollTime, 
                    true); // execute only once 
        } // InitializeSocketTimeoutHandler
 
        private static void TimeoutConnections(Object state, Boolean wasSignalled)
        {
            DateTime currentTime = DateTime.UtcNow;
 
            lock (_connections)
            { 
                foreach (DictionaryEntry entry in _connections) 
                {
                    PortConnection connection = (PortConnection)entry.Value; 
                    if (DateTime.Now - connection.LastUsed > _portLifetime)
                        connection.Port.Dispose();
                }
            } 

            _registeredWaitHandle.Unregister(null); 
            _registeredWaitHandle = 
                ThreadPool.UnsafeRegisterWaitForSingleObject(
                    _socketTimeoutWaitHandle, 
                    _socketTimeoutDelegate,
                    "IpcConnectionTimeout",
                    _socketTimeoutPollTime,
                    true); // execute only once 
        } // TimeoutConnections
 
        // The key is expected to of the form portName 
        public IpcPort GetConnection(String portName, bool secure, TokenImpersonationLevel level, int timeout)
        { 
            PortConnection connection = null;
            lock (_connections)
            {
                bool cacheable = true; 
                if (secure)
                { 
                  try 
                  {
                    WindowsIdentity currentId = WindowsIdentity.GetCurrent(true/*ifImpersonating*/); 
                    if (currentId != null)
                    {
                      cacheable = false;
                      currentId.Dispose(); 
                    }
                  } 
                  catch(Exception) 
                  {
                      cacheable = false; 
                  }
                }

                if (cacheable) 
                {
                    connection = (PortConnection)_connections[portName]; 
                } 
                if (connection == null || connection.Port.IsDisposed)
                { 
                    connection = new PortConnection(IpcPort.Connect(portName, secure, level, timeout));
                    connection.Port.Cacheable = cacheable;
                }
                else 
                {
                    // Remove the connection from the cache 
                    _connections.Remove(portName); 
                }
            } 
            return connection.Port;
        } // GetSocket

        public void ReleaseConnection(IpcPort port) 
        {
            string portName = port.Name; 
            PortConnection connection = (PortConnection)_connections[portName]; 
            if (port.Cacheable && (connection == null || connection.Port.IsDisposed))
            { 
                lock(_connections)
                {
                    _connections[portName] = new PortConnection(port);
                } 
            }
            else 
            { 
                // there should have been a connection, so let's just close
                //   this socket. 
                port.Dispose();
            }
        } // ReleasePort
 

    } // ConnectionCache 
 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
//============================================================================
//  File:       PortCache.cs 
//  Author:   [....]@Microsoft.Com 
//  Summary:    Implements a cache for port handles
// 
//=========================================================================

using System;
using System.Collections; 
using System.Threading;
using System.Security.Principal; 
 
namespace System.Runtime.Remoting.Channels.Ipc
{ 
    internal class PortConnection
    {
        private IpcPort _port;
        private DateTime _socketLastUsed; 

        internal PortConnection(IpcPort port) 
        { 
            _port = port;
            _socketLastUsed = DateTime.Now; 
        }

        internal IpcPort Port { get { return _port; } }
        internal DateTime LastUsed { get { return _socketLastUsed; } } 
    }
 
    internal class ConnectionCache 
    {
        // collection of RemoteConnection's. 
        private static Hashtable _connections = new Hashtable();

        // socket timeout data
        private static RegisteredWaitHandle _registeredWaitHandle; 
        private static WaitOrTimerCallback _socketTimeoutDelegate;
        private static AutoResetEvent _socketTimeoutWaitHandle; 
        private static TimeSpan _socketTimeoutPollTime = TimeSpan.FromSeconds(10); 
        private static TimeSpan _portLifetime = TimeSpan.FromSeconds(10);
 
        static ConnectionCache()
        {
            InitializeConnectionTimeoutHandler();
        } 

        private static void InitializeConnectionTimeoutHandler() 
        { 
            _socketTimeoutDelegate = new WaitOrTimerCallback(TimeoutConnections);
            _socketTimeoutWaitHandle = new AutoResetEvent(false); 
            _registeredWaitHandle =
                ThreadPool.UnsafeRegisterWaitForSingleObject(
                    _socketTimeoutWaitHandle,
                    _socketTimeoutDelegate, 
                    "IpcConnectionTimeout",
                    _socketTimeoutPollTime, 
                    true); // execute only once 
        } // InitializeSocketTimeoutHandler
 
        private static void TimeoutConnections(Object state, Boolean wasSignalled)
        {
            DateTime currentTime = DateTime.UtcNow;
 
            lock (_connections)
            { 
                foreach (DictionaryEntry entry in _connections) 
                {
                    PortConnection connection = (PortConnection)entry.Value; 
                    if (DateTime.Now - connection.LastUsed > _portLifetime)
                        connection.Port.Dispose();
                }
            } 

            _registeredWaitHandle.Unregister(null); 
            _registeredWaitHandle = 
                ThreadPool.UnsafeRegisterWaitForSingleObject(
                    _socketTimeoutWaitHandle, 
                    _socketTimeoutDelegate,
                    "IpcConnectionTimeout",
                    _socketTimeoutPollTime,
                    true); // execute only once 
        } // TimeoutConnections
 
        // The key is expected to of the form portName 
        public IpcPort GetConnection(String portName, bool secure, TokenImpersonationLevel level, int timeout)
        { 
            PortConnection connection = null;
            lock (_connections)
            {
                bool cacheable = true; 
                if (secure)
                { 
                  try 
                  {
                    WindowsIdentity currentId = WindowsIdentity.GetCurrent(true/*ifImpersonating*/); 
                    if (currentId != null)
                    {
                      cacheable = false;
                      currentId.Dispose(); 
                    }
                  } 
                  catch(Exception) 
                  {
                      cacheable = false; 
                  }
                }

                if (cacheable) 
                {
                    connection = (PortConnection)_connections[portName]; 
                } 
                if (connection == null || connection.Port.IsDisposed)
                { 
                    connection = new PortConnection(IpcPort.Connect(portName, secure, level, timeout));
                    connection.Port.Cacheable = cacheable;
                }
                else 
                {
                    // Remove the connection from the cache 
                    _connections.Remove(portName); 
                }
            } 
            return connection.Port;
        } // GetSocket

        public void ReleaseConnection(IpcPort port) 
        {
            string portName = port.Name; 
            PortConnection connection = (PortConnection)_connections[portName]; 
            if (port.Cacheable && (connection == null || connection.Port.IsDisposed))
            { 
                lock(_connections)
                {
                    _connections[portName] = new PortConnection(port);
                } 
            }
            else 
            { 
                // there should have been a connection, so let's just close
                //   this socket. 
                port.Dispose();
            }
        } // ReleasePort
 

    } // ConnectionCache 
 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
